package net.entelijan.cobean.bind.impl;

import java.util.Arrays;

import net.entelijan.cobean.table.IBeanTreater;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

public class SpringBeanTreater implements IBeanTreater {

	public SpringBeanTreater() {
		super();
	}

	public <T> boolean equals(T lhs, T rhs) {
		boolean re = false;
		if (rhs == null && lhs == null) {
			re = true;
		} else if (rhs != null && lhs != null) {
			T trhs = getTarget(rhs);
			T tlhs = getTarget(lhs);
			re = trhs.hashCode() == tlhs.hashCode() && trhs.equals(tlhs);
		}
		return re;
	}

	public boolean isWrapped(Object model) {
		return isCglibProxy(model)
				|| isDynamicProxy(model);
	}

	public boolean isCglibProxy(Object model) {
		boolean re = false;
		if (model != null) {
			re = isCglibProxyFromClass(model.getClass());
		}
		return re;
	}

	public boolean isDynamicProxy(Object model) {
		boolean re = false;
		if (model != null) {
			re = isDynamicProxyFromClass(model.getClass());
		}
		return re;
	}

	public boolean isCglibProxyFromClass(Class<?> clazz) {
		return clazz.getName().indexOf("ByCGLIB") >= 0;
	}

	public boolean isDynamicProxyFromClass(Class<?> clazz) {
		return clazz.getName().indexOf("Proxy") >= 0;
	}

	public Class<?> getOriginalClass(Class<?> clazz) {
		if (isCglibProxyFromClass(clazz)) {
			return getOriginalClassFromCglib(clazz);
		}
		if (isDynamicProxyFromClass(clazz)) {
			return getOriginalClassFromDynamicProxy(clazz);
		}
		throw new UnsupportedOperationException(clazz + " is not a known proxy");
	}

	public Class<?> getOriginalClassFromCglib(Class<?> cglibClass) {
		return cglibClass.getSuperclass();
	}

	public Class<?> getOriginalClassFromDynamicProxy(
			Class<?> wrappedClass) {
		throw new IllegalStateException("Not yet impl. class='"
				+ wrappedClass.getName() + "' interfaces='"
				+ Arrays.toString(wrappedClass.getInterfaces()) + "'");
	}

	public boolean isProxy(Class<?> clazz) {
		return isCglibProxy(clazz) || isDynamicProxy(clazz);
	}

	public <T> T getTarget(T obj) {
		T re;
		if (isCglibProxy(obj)) {
			re = targetFromCglibProxy(obj);
		} else if (isDynamicProxy(obj)) {
			re = targetFromDynamicProxy(obj);
		} else { // Not wrapped
			re = obj;
		}
		return re;
	}

	private <T> T targetFromDynamicProxy(T obj) {
		throw new IllegalStateException("Not yet implemented");
	}

	@SuppressWarnings("unchecked")
	private <T> T targetFromCglibProxy(T obj) {
		BeanWrapper bw = new BeanWrapperImpl(obj);
		T re = (T) bw.getPropertyValue("targetSource.target");
		return re;
	}


	
}
